/*
 * @Author: 陈鑫茹 2182688619@qq.com
 * @Date: 2025-06-27 10:17:18
 * @LastEditors: 陈鑫茹 2182688619@qq.com
 * @LastEditTime: 2025-06-28 23:19:28
 * @FilePath: \见习1\Calculator.java
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.JButton;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.Timer;

import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Dimension;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

//继承JFrame 为了直接复用swing框架中窗口管理的能力
//为了子类可以直接调用 JFrame public 的方法

//ApplicationListener 是java中事件处理机制的核心部分
//为了建立计算器组件和用户操作之间的响应机制

public class Calculator extends JFrame implements ActionListener{
    //声明界面组件
    //上下两个容器面板 文本框区域 按钮区域
    private JPanel north,center;
    //文本框 显示计算器过程或者结果或者日期时间
    private JTextField field;
    //按钮
    private JButton[] btns;

    //***** 定时器，用于自动更新时间 *****
    private Timer clockTimer;

    //***** 音乐播放相关变量  *****
    private Clip clip;
    private boolean isMusicPlaying = false;

    //初始化窗口 - 构造器 构造方法 无参构造器
    public Calculator(){
        // 设置窗口title
        setTitle("计算器:");

        //设置窗口大小
        setSize(700,700);

        //设置窗口关闭程序
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        //设置窗口居中显示
        setLocationRelativeTo(null);

        //初始化见面组件
        initComponent();

        //设置窗口显示
        setVisible(true);
        
        //***** 初始化时钟定时器（每秒触发一次）*****
        clockTimer = new Timer(1000, e -> updateClock());
        clockTimer.setInitialDelay(0);  //将计时器的初始延迟设置为 0 毫秒
        clockTimer.start(); //启动计时器
        //*****
    }
    //***** 按键提示音 *****------------------------------------------------------------
    private void playClickSound() {
        try {
            File audioFile = new File("D:/桌面/陈鑫茹/见习1/dudu.wav"); 
            AudioInputStream audioStream = AudioSystem.getAudioInputStream(audioFile);
            AudioFormat format = audioStream.getFormat();
            DataLine.Info info = new DataLine.Info(Clip.class, format);
            Clip clip = (Clip) AudioSystem.getLine(info);
            clip.open(audioStream);
            clip.start();
        } catch (UnsupportedAudioFileException | LineUnavailableException | IOException e) {
            e.printStackTrace();
     }
    }
    //初始化见面组件
     private void initComponent(){
        ////System.out.println("initComponent");
        //创建面板容器
        //面板容器 文本框区域
        north = new JPanel();
        //面板容器 按钮区域
        center = new JPanel();
 
        //***** 设置面板背景颜色 *****
        north.setBackground(new Color(240, 240, 240)); // 浅灰色
        center.setBackground(new Color(220, 220, 220)); // 中灰色
        //*****

        //文本框 显示计算过程,结果或者日期时间
        field = new JTextField();
        //设置输入框大小
        field.setPreferredSize(new Dimension(700,150));
        //禁用文字输入 禁止通过电脑键盘输入编辑
        field.setEditable(false);
        //设置输入框中文字大小
        field.setFont (new Font("SansSerif",Font.BOLD,35));
        //按钮文本内容

        String[] str = new String[]{
            "(", ")", "^", "%",
            "7", "8", "9", "+",
            "4", "5", "6", "-",
            "1", "2", "3", "×",
            "0", ".", "=", "÷",
            "C", "B", "T", "S"
        };

        //按钮数组
        btns = new JButton[str.length];
        for(int i = 0;i < btns.length; i++){
            btns[i] = new JButton(str[i]);
            btns[i].setFont (new Font("SansSerif",Font.BOLD,25));
            //***** 设置按钮样式    *****
            if (i >= 16) { // 功能按钮 (C, B, T, S)
                btns[i].setBackground(new Color(255, 100, 100)); // 红色系
                btns[i].setForeground(Color.WHITE);
            } else if (i % 4 == 3) { // 操作符按钮 (+, -, ×, ÷, =)
                btns[i].setBackground(new Color(100, 150, 255)); // 蓝色系
                btns[i].setForeground(Color.WHITE);
            } else { // 数字按钮
                btns[i].setBackground(new Color(220, 220, 220)); // 浅灰色
                btns[i].setForeground(Color.BLACK);
            }
            
            // 设置按钮边框样式
            btns[i].setBorder(UIManager.getBorder("Button.border"));
            //*****
        }
        //将组件放到窗口中
        //设置布局管理
        //north 顶部面板 使用 BorderLayout 边界布局

        north.setLayout(new BorderLayout());
        //center 中间面板 使用 5行4列 的 网格 布局
        center.setLayout(new GridLayout(6,4));
        //组件设置
        //field 文本框 添加到 north 顶部面板 使用BorderLayout 居中

        north.add(field,BorderLayout.CENTER);
        //btns 按钮 添加到 center 面板 
        for(JButton btn : btns){
            center.add(btn); // 通过便利将所按钮添加到 center 面板
        }

        north.add(field,BorderLayout.CENTER);
        //将north 顶部面板 添加到窗口中
        add(north,BorderLayout.NORTH);
        //将center 顶部面板 添加到窗口中
        add(center);

        //绑定按钮的监听事件
        for(JButton btn : btns){
          btn.addActionListener(this);   // this 代表当前对象实例
        }
     }

    //处理按键文本
     private void setBtnText(String text){
        //System.out.println("setBtnText:" + text);
        //System.out.println("text length:" + text.length());
        //System.out.println("filed text length:" + filed.getText().length());
        switch (text){
            case "C":   
                //清空功能
                field.setText("");
                //System.out.println("C");
                break;
            case "B":
                //退格功能
                // 1.获取输入框的内容
                String numText = field.getText();
                // 2.两种情况 isEmpty() 或者 .length()等方法判断
                if(numText.length() != 0){
                    //输入框的内容不为空
                    //System.out.println("输入框的内容不为空:" + numText);
                    // numText 的长度-1
                    String lastText = numText.substring(0, numText.length() - 1);
                    //System.out.println("lastText :" + lastText);
                    //将截取后的文本设置到输入框
                    field.setText(lastText);
                }else{
                    //System.out.println("输入框的内容为空");
                }
                //System.out.println("B");
                break;
            case "T":
                //显示当前日期时间
                showDateTime(); //*****
                //System.out.println("T:显示时间");
                break;
            case "S":
                // 音乐播放/暂停功能
                toggleMusic();
                //System.out.println("S:自定义功能,比如弹钢琴");
                break;
            case "=":
                //System.out.println("=:执行计算功能");
                calculate();
                //用户输入 1+1 我们执行计算操作 然后将结果展示到文本框
                //用户输入 1+1
                field.getText();
                //我们执行计算操作
                //然后将结果展示到文本框
                //field.setText();
                break;         
            default:
                // 按下数字键或者运算符 要把文字放到输入框中
                // 如果之前输入框中有文字 做拼接
                String oldText = field.getText();
                // ***** 定义操作符集合 ***** -------------------------------------------------------------------
                 Set<String> operators = new HashSet<>(Arrays.asList("+", "-", "×", "÷", "^")); 
                 boolean isValid = true; 
                 // 验证操作符 
                 if (operators.contains(text)) { // 操作符不能出现在开头
                     if (oldText.isEmpty()) { 
                        isValid = false; 
                    } else { 
                        // 操作符不能连续出现 
                        String lastChar = oldText.substring(oldText.length() - 1);
                         if (operators.contains(lastChar)) { 
                            isValid = false; 
                        } 
                    } 
                } 
                //****** 验证小数点 如果前目没有数字 那么按下小数点 自动补充为0 ******
                 else if (text.equals(".")) {
                if (oldText.isEmpty()) { 
                    // 输入框为空时自动补0
                    field.setText("0.");
                    return; // 直接返回，不执行后续拼接
                } else {
                    String lastChar = oldText.substring(oldText.length() - 1);
                    if (lastChar.equals(".")) {
                        isValid = false; 
                        } 
                    }
                }    

                if (!isValid) {
                    return; 
                 }
                //---------------------------------------------------------------------------------------------------------
                field.setText(oldText + text); //作添加 不计算
                break; 
        }
        //按下数字键 要把文字放到输入框中
     }

     //***** 显示当前日期时间的方法 *****---------------------------------------------------------------
    private void showDateTime() {
        System.out.println("尝试显示日期时间..."); // 添加日志
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String formattedDateTime = now.format(formatter);
        field.setText(formattedDateTime);
         // 确保定时器运行
        if (!clockTimer.isRunning()) {
            clockTimer.start();
        }
        updateClock(); // 立即更新时间  
    }
    
    //***** 添加时间 *****-----------------------------------------------------------------------------------
    private void updateClock() {
        // 使用正则表达式检查当前文本是否为时间格式
        String currentText = field.getText();
        if (currentText.matches("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}")) {
            LocalDateTime now = LocalDateTime.now();
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            field.setText(now.format(formatter));
        } else {
            // 如果用户已输入其他内容，停止定时器
            clockTimer.stop();
        }
    }
    //--------------------------------------------------------------------------------------------------------
    
    //执行计算功能
     private void calculate(){  //参数可传可不传
                //System.out.println("=:执行计算功能");
                //用户输入 1+1 我们执行计算操作 然后将结果展示到文本框
                //用户输入 1+1
                //如果表达式当中有× ÷要替换为 * /
                String expression = field.getText();
                // *******替换乘除符号 *******---------------------------------------------------------------------
                expression = expression.replace("×", "*").replace("÷", "/");
                // 添加：将^替换为JavaScript的幂运算符号**  
                expression = expression.replace("^", "**"); 
                //我们执行计算操作 使用js计算引擎
                ScriptEngineManager manager = new ScriptEngineManager();
                //初始化计算引擎 使用 javascript 解析数学表达式
                ScriptEngine engine = manager.getEngineByName("javascript");
                try {// try 中放的是可能出现异常的代码
                    //开始计算
                    Object result = engine.eval(expression);
                    // 处理浮点数精度，保留6位小数（可按需调整位数） 
                    java.text.DecimalFormat df = new java.text.DecimalFormat("#.######");
                     String formattedResult = df.format(result);
                    // 然后将结果展示到文本框
                    field.setText(formattedResult);
                    //field.setText(result.toString());
                } catch(ScriptException e) {
                     // catch 中放的是异常的处理方式
                    field.setText("运算错误:");
                    e.printStackTrace();
                //然后将结果展示到文本框
                //field.setText();
    
                setVisible(true);
             }
     }

    @Override
    public void actionPerformed(ActionEvent a) {
        Object source = a.getSource();  // 获取事件源对象（即触发此事件的组件）
        if (source instanceof JButton) {    // 检查事件源是否为 JButton 类型
            JButton btn = (JButton) source; // 将事件源强制转换为 JButton 类型
            String text = btn.getText();    // 获取按钮上显示的文本
            playClickSound(); // 添加这一行来播放按键提示音
            commonLogic(text);
            // 这里添加此方法特有的额外逻辑
        }
    }
    private void commonLogic(String text) {
        setBtnText(text);   // 设置按钮文本（具体实现由 setBtnText 方法决定）
        // 其他共同的逻辑代码
    }
    
    // 音乐播放控制方法
    private void toggleMusic() {
        if (isMusicPlaying) {
            stopMusic();
        } else {
            playMusic();
        }
    }
    //添加音乐
    private void playMusic() {
        try {
            // 加载音频文件
            File audioFile = new File("D:/桌面/陈鑫茹/见习1/my.wav"); // 请替换为实际音频文件路径
            
            if (!audioFile.exists()) {
                field.setText("音乐文件不存在");
                return;
            }
            
            AudioInputStream audioStream = AudioSystem.getAudioInputStream(audioFile);
            AudioFormat format = audioStream.getFormat();
            DataLine.Info info = new DataLine.Info(Clip.class, format);
            
            if (!AudioSystem.isLineSupported(info)) {
                field.setText("不支持的音频格式");
                return;
            }
            
            clip = (Clip) AudioSystem.getLine(info);
            clip.open(audioStream);
            clip.start();
            clip.loop(Clip.LOOP_CONTINUOUSLY); // 循环播放
            
            isMusicPlaying = true;
            field.setText("音乐已播放");
        } catch (UnsupportedAudioFileException | LineUnavailableException | IOException e) {
            field.setText("播放音乐失败");
            e.printStackTrace();
        }
    }
    //音乐暂停
    private void stopMusic() {
        if (clip != null && clip.isRunning()) {
            clip.stop();
            clip.close();
            isMusicPlaying = false;
            field.setText("音乐已停止");
        }
    }
    
    // 窗口关闭时释放资源
    @Override
    public void dispose() {
        stopMusic();
        super.dispose();
    }
    public static void main(String[] args){
        //System.out.println("hell,Calculator");
        //创建类的对象 - 线程不安全
        //new Calculator();

        //是 Java Swing 开发中确保线程安全
        SwingUtilities.invokeLater(Calculator::new);
    }
}